package com.mangatta.cloud.dao;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import com.mangatta.cloud.ec2.Ec2Instance;

import java.util.*;

public class InstanceDetailDao extends DbHelper {
    private static final String TAG = InstanceDetailDao.class.getSimpleName();

    public InstanceDetailDao(Context context) {
        super(context);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        Log.d(TAG, "Created table");
        super.onCreate(db);//create tables.
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Log.d(TAG, "on Updated");
    }

    public List<Ec2Instance> getInstances(boolean includeInactive) {
        List<Ec2Instance> allInstances = getInstances();
        if (includeInactive || allInstances == null) {
            return allInstances;
        }
        List<Ec2Instance> activeInstances = new ArrayList<Ec2Instance>();
        for (Ec2Instance instance : allInstances) {
            if (instance.isActive()) {
                activeInstances.add(instance);
            }
        }
        return activeInstances;
    }

    public List<Ec2Instance> getInstances() {
        SQLiteDatabase db = getReadableDatabase();
        List<Ec2Instance> ec2Instances = new ArrayList<Ec2Instance>();

        try {
            Cursor cursor = db.query(InstanceDetailTable.TABLE_INSTANCE_DETAILS, null, null, null, null, null, null);

            if (cursor != null) {
                while (cursor.moveToNext()) {
                    String instanceId = cursor.getString(cursor.getColumnIndex(InstanceDetailTable.C_INSTANCE_ID));
                    String name = cursor.getString(cursor.getColumnIndex(InstanceDetailTable.C_NAME));
                    int state = cursor.getInt(cursor.getColumnIndex(InstanceDetailTable.C_STATE));
                    Ec2Instance ec2Instance = new Ec2Instance(instanceId, name, state);
                    ec2Instances.add(ec2Instance);
                }
                cursor.close();
            }
        } finally {
            db.close();
        }
        return ec2Instances;
    }

    /**
     * Given the latest set of instances available, persist them in the DB
     *
     * @param newEc2Instances - instances that need to be persisted in the DB
     * @return instances that cant be persisted
     */
    public List<Ec2Instance> persistInstanceDetail(List<Ec2Instance> newEc2Instances) {
        List<Ec2Instance> existingInstances = getInstances();
        List<Ec2Instance> missingInstances = missingInstances(existingInstances, newEc2Instances);

        SQLiteDatabase db = getWritableDatabase();

        try {
            // Delete missing instances
            if (missingInstances != null && missingInstances.size() > 0) {
                List<String> instanceIds = getInstanceIds(missingInstances);
                if (instanceIds != null && instanceIds.size() > 0) {
                    Log.d("INSTANCES", instanceIds.toString());
                    String[] instanceArray = new String[instanceIds.size()];
                    for (int i = 0; i < instanceIds.size(); i++) {
                        instanceArray[i] = instanceIds.get(i);
                    }
                    db.delete(InstanceDetailTable.TABLE_INSTANCE_DETAILS, InstanceDetailTable.C_INSTANCE_ID + " in (?)", instanceArray);
                }
                // TODO: Delete from alarm_configurations table also
            }

            List<Ec2Instance> failedInstances = new ArrayList<Ec2Instance>();
            if (newEc2Instances != null && newEc2Instances.size() > 0) {
                // Try inserting other instances. If they exist already, catch the exception and proceed with saving the
                // rest of the instances.
                ContentValues contentValues = new ContentValues();
                for (Ec2Instance ec2Instance : newEc2Instances) {
                    contentValues.clear();
                    contentValues.put(InstanceDetailTable.C_INSTANCE_ID, ec2Instance.getInstanceId());
                    contentValues.put(InstanceDetailTable.C_CREATED_AT, Calendar.getInstance().getTime().getTime());
                    contentValues.put(InstanceDetailTable.C_STATE, ec2Instance.getState());
                    contentValues.put(InstanceDetailTable.C_NAME, ec2Instance.getName());
                    try {
                        db.insertWithOnConflict(InstanceDetailTable.TABLE_INSTANCE_DETAILS, null, contentValues, SQLiteDatabase.CONFLICT_IGNORE);
                    } catch (SQLException e) {
                        Log.e(TAG, "Instance cant be persisted", e);
                        failedInstances.add(ec2Instance);
                    }
                }
            }
            db.close();
            return failedInstances;
        } finally {
            if (db != null && db.isOpen()) {
                db.close();
            }
        }
    }


    private List<String> getInstanceIds(List<Ec2Instance> instances) {
        if (instances == null) {
            return null;
        }
        List<String> names = new ArrayList<String>();
        for (Ec2Instance instance : instances) {
            names.add(instance.getInstanceId());
        }
        return names;
    }

    private List<Ec2Instance> missingInstances(List<Ec2Instance> existingInstances, List<Ec2Instance> newInstances) {
        if (newInstances == null || existingInstances == null) {
            return existingInstances;
        }
        Map<String, Ec2Instance> newEc2InstanceMap = new HashMap<String, Ec2Instance>();
        for (Ec2Instance newInstance : newInstances) {
            newEc2InstanceMap.put(newInstance.getInstanceId(), newInstance);
        }

        List<Ec2Instance> missingInstances = new ArrayList<Ec2Instance>();
        for (Ec2Instance existingInstance : existingInstances) {
            if (!newEc2InstanceMap.containsKey(existingInstance.getInstanceId())) {
                missingInstances.add(existingInstance);
            }
        }
        return missingInstances;
    }
}
